#ifndef __I_THREAD_H__
#define __I_THREAD_H__

#include <zlib/lib/Ink_pthread.h>
#include <zlib/lib/Ink_time.h>
#include <zlib/lib/I_Ptr.h>
#include "I_Lock.h"
#include "P_Queue.h"
#include "I_Event.h"

#define MAX_EVENT_THREAD	128
//64k
#define THREAD_PRIVATE_DATA (64 * 1024)

extern bool event_loop_run;

typedef void *(*ThreadFunction)(void *arg);

class Thread
{
public:
	Thread();
	virtual ~Thread();

	static ink_hrtime cur_time;
	static ink_thread_key thread_data_key;

	ink_thread start(const char *name, ThreadFunction f, void *a, int detached = 0, size_t stacksize = 0, void *stack = NULL);

	virtual void execute() {};
	void set_specific();

	ink_thread tid;
	Ptr<ProxyMutex> mutex_ptr;
private:
	Thread(const Thread &);
	Thread &operator=(const Thread &);
};

inline Thread *this_thread()
{
	return (Thread *)ink_thread_getspecific(Thread::thread_data_key);
}


//R:REGULAR		D:DEDICATED
enum ThreadType{
	R = 0,
	D
};

class EThread : public Thread
{
public:
	EThread(int anid);//ThreadType = R
	EThread(Event *e);//ThreadType = D
	virtual ~EThread();

	int id;
	EThread **ethreads_tobe_signalled;
	int n_ethreads_tobe_signalled;
	char *thread_private_data;

	virtual void execute();

	BlockNotifyQueue notifyQueue;
	PriorityQueue timeQueue;
	NegativeQueue negQueue;

	Event *schedule_imm(Continuation *cont, int callback_event = EVENT_IMMDIATE);
	Event *schedule_imm_signal(Continuation *cont, int callback_event = EVENT_IMMDIATE);
	Event *schedule_at(Continuation *cont, ink_hrtime t, int callback_event = EVENT_INTERVAL);
	Event *schedule_every(Continuation *cont, ink_hrtime t, int callback_event = EVENT_INTERVAL);

	Event *schedule_imm_local(Continuation *cont, int callback_event = EVENT_IMMDIATE);
	Event *schedule_at_local(Continuation *cont, ink_hrtime t, int callback_event = EVENT_INTERVAL);
	Event *schedule_every_local(Continuation *cont, ink_hrtime t, int callback_event = EVENT_INTERVAL);
	
	void (*signal_hook)(EThread *);//用于异步回调hook
private:
	EThread();
	EThread(const EThread &);
	EThread &operator=(const EThread &);
	void process_event(Event *e, int calling_code);

	Event *schedule(Event *e, bool fast_signal = false);
	Event *schedule_local(Event *e);

	ThreadType t;
	Event *oneevent;
};

inline EThread *this_ethread()
{
	return (EThread *)ink_thread_getspecific(Thread::thread_data_key);
}

#define ETHREAD_GET_PRIVATE(ethread, offset)	\
	((void *)(((ethread)->thread_private_data) + (offset)))

#endif //__I_THREAD_H__
